package com.sunday.common.core.utils;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.util.Date;
import java.util.regex.Pattern;

/**
 * jdk1.8 LocalDateTime util 类
 * format 开头方法均为时间格式化，最终转换为 String
 * convert 开头方法均为时间转换，最终转换为 LocalDateTime/LocalDate/LocalTime
 *
 * @author zsy
 * @since 2022/10/10
 */
public class DateTimeUtils {

    public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HHmmss");
    public static final DateTimeFormatter MONTH_FORMATTER = DateTimeFormatter.ofPattern("yyyyMM");
    public static final DateTimeFormatter YEAR_FORMATTER = DateTimeFormatter.ofPattern("yyyy");
    public static final DateTimeFormatter SHORT_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyMMdd");
    public static final DateTimeFormatter SHORT_DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyMMddHHmmss");
    public static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
    public static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
    public static final DateTimeFormatter DATE_FORMATTER_SPLIT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    public static final DateTimeFormatter MONTH_FORMATTER_SPLIT = DateTimeFormatter.ofPattern("yyyy-MM");
    public static final DateTimeFormatter DATETIME_FORMATTER_SPLIT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    public static final DateTimeFormatter DATETIME_MS_FORMATTER_SPLIT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
    public static final DateTimeFormatter DATETIME_FORMATTER_SPLIT_ZH = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");

    /**
     * 是否当天
     *
     * @param date
     * @return {@link boolean}
     */
    public static boolean isToday(LocalDate date) {
        return LocalDate.now().equals(date);
    }

    /**
     * 计算当天剩余的秒数
     *
     * @return {@link long}
     */
    public static long calculateRemainingSecondsOfDay() {
        LocalDateTime currTime = LocalDateTime.now();
        LocalDateTime maxTime = currTime.toLocalDate().atTime(LocalTime.MAX);
        return Duration.between(currTime, maxTime).getSeconds();
    }

    /**
     * 当前的 Epoch 秒数
     *
     * @return {@link long}
     */
    public static long getCurrentEpochSeconds() {
        return LocalDateTime.now().atZone(ZoneOffset.systemDefault()).toEpochSecond();
    }

    /**
     * 当前的 Epoch 毫秒数
     *
     * @param dateTime
     * @return {@link long}
     */
    public static long convertLocalDateTimeToEpochMilli(LocalDateTime dateTime) {
        return dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    /****************************************    【转换】  java.util.Date  **********************************************/


    /**
     * LocalDate 转换 Date
     *
     * @param date
     * @return {@link Date}
     */
    public static Date convertUDate(LocalDate date) {
        return Date.from(date.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * LocalDateTime 转换 Date
     *
     * @param dateTime
     * @return {@link Date}
     */
    public static Date convertUDate(LocalDateTime dateTime) {
        return Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant());
    }


    /****************************************    【适配】  日期时间  **********************************************/

    /**
     * 初始化 LocalDateTime 正则信息
     */
    private final static Object[][] dateTimePatterns = {
            {
                    Pattern.compile("^(\\d{4})(\\-)(\\d{2})(\\-)(\\d{2})(\\s+)(\\d{2})(\\:)(\\d{2})(\\:)(\\d{2})$"), DATETIME_FORMATTER_SPLIT
            },//yyyy-MM-dd HH:mm:ss
            {
                    Pattern.compile("^\\d{14}$"), DATETIME_FORMATTER
            }//yyyyMMddHHmmss
    };

    /**
     * 通过传入时间字符串 DateTime 获取正则信息
     *
     * @param dateTime
     * @return {@link DateTimeFormatter}
     */
    public static DateTimeFormatter dateTimeFormatAdapter(String dateTime) {
        DateTimeFormatter format = null;
        Pattern p;
        for (Object[] item : dateTimePatterns) {
            p = (Pattern) item[0];
            if (p.matcher(dateTime).matches()) {
                format = (DateTimeFormatter) item[1];
                break;
            }
        }
        assert format != null : "can't find date time formatter for " + dateTime;
        return format;
    }

    /**
     * 通过传入时间字符串 获取 LocalDateTime
     * 需要传入时间格式
     * 例如：
     * yyyy-MM-dd HH:mm:ss
     * yyyyMMddHHmmss
     * 否则异常
     *
     * @param dateTime
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime convertDateTimeAdapter(String dateTime) {
        return LocalDateTime.parse(dateTime, dateTimeFormatAdapter(dateTime));
    }

    /****************************************    【格式化】  日期  **********************************************/

    /**
     * 返回当前的时间 yyMMdd
     *
     * @return {@link String}
     */
    public static String formatShortDate() {
        return LocalDate.now().format(SHORT_DATE_FORMATTER);
    }

    /**
     * 返回当前的时间 yyyyMMdd
     *
     * @return {@link String}
     */
    public static String formatDate() {
        return formatDate(LocalDate.now());
    }

    /**
     * 根据 LocalDate 采用默认 yyyyMMdd 格式 获取 String
     *
     * @param date
     * @return {@link String}
     */
    public static String formatDate(LocalDate date) {
        return date.format(DATE_FORMATTER);
    }

    /**
     * 根据 格式 返回当前日期
     *
     * @param pattern
     * @return {@link String}
     */
    public static String formatDate(String pattern) {
        return formatDate(LocalDate.now(), pattern);
    }

    /**
     * 根据指定 LocalDate 和 格式 返回 String
     *
     * @param date
     * @param pattern
     * @return {@link String}
     */
    public static String formatDate(LocalDate date, String pattern) {
        return date.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 根据 LocalDate 采用默认 yyyy-MM-dd 格式 获取 String
     *
     * @param date
     * @return {@link String}
     */
    public static String formatDateSplit(LocalDate date) {
        return date.format(DATE_FORMATTER_SPLIT);
    }

    /**
     * 根据 LocalDateTime 采用默认"yyyyMMdd" 格式 获取 String
     *
     * @param datetime
     * @return {@link String}
     */
    public static String formatDateOfDateTime(LocalDateTime datetime) {
        return datetime.format(DATE_FORMATTER);
    }

    /**
     * 根据 LocalDateTime 采用默认"yyyy-MM-dd" 格式 获取 String
     *
     * @param datetime
     * @return {@link String}
     */
    public static String formatDateSplitOfDateTime(LocalDateTime datetime) {
        return datetime.format(DATE_FORMATTER_SPLIT);
    }

    /****************************************    【格式化】  时间  **********************************************/

    /**
     * 返回当前的时间 HHmmss
     *
     * @return {@link String}
     */
    public static String formatTime() {
        return formatTime(LocalTime.now());
    }

    /**
     * 根据 LocalTime 采用默认 HHmmss 格式 获取 String
     *
     * @param time
     * @return {@link String}
     */
    public static String formatTime(LocalTime time) {
        return time.format(TIME_FORMATTER);
    }

    /**
     * 根据 格式 返回当前时间
     *
     * @param pattern
     * @return {@link String}
     */
    public static String formatTime(String pattern) {
        return formatTime(LocalTime.now(), pattern);
    }

    /**
     * 根据指定 LocalTime 和 格式 返回 String
     *
     * @param time
     * @param pattern
     * @return {@link String}
     */
    public static String formatTime(LocalTime time, String pattern) {
        return time.format(DateTimeFormatter.ofPattern(pattern));
    }

    /****************************************    【格式化】  日期时间  **********************************************/

    /**
     * 返回当前的时间 yyMMddHHmmss
     *
     * @return {@link String}
     */
    public static String formatShortDateTime() {
        return LocalDateTime.now().format(SHORT_DATETIME_FORMATTER);
    }

    /**
     * 返回当前的时间 yyyyMMddHHmmss
     *
     * @return {@link String}
     */
    public static String formatDateTime() {
        return formatDateTime(LocalDateTime.now());
    }

    /**
     * 根据 LocalDateTime 采用默认 yyyyMMddHHmmss 格式 获取 String
     *
     * @param datetime
     * @return {@link String}
     */
    public static String formatDateTime(LocalDateTime datetime) {
        return datetime.format(DATETIME_FORMATTER);
    }

    /**
     * 根据 格式 返回当前日期时间
     *
     * @param pattern
     * @return {@link String}
     */
    public static String formatDateTime(String pattern) {
        return formatDateTime(LocalDateTime.now(), pattern);
    }

    /**
     * 根据指定 LocalDateTime 和 格式 返回 String
     *
     * @param datetime
     * @param pattern
     * @return {@link String}
     */
    public static String formatDateTime(LocalDateTime datetime, String pattern) {
        return datetime.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 返回当前的时间 yyyy-MM-dd HH:mm:ss
     *
     * @return {@link String}
     */
    public static String formatDateTimeSplit() {
        return formatDateTimeSplit(LocalDateTime.now());
    }

    /**
     * 根据 LocalDateTime 采用默认 yyyy-MM-dd HH:mm:ss 格式 获取 String
     *
     * @param datetime
     * @return {@link String}
     */
    public static String formatDateTimeSplit(LocalDateTime datetime) {
        return datetime.format(DATETIME_FORMATTER_SPLIT);
    }

    /**
     * 返回当前的时间  yyyy-MM-dd HH:mm:ss.SSS
     *
     * @return {@link String}
     */
    public static String formatDateTimeMsSplit() {
        return formatDateTimeMsSplit(LocalDateTime.now());
    }

    /**
     * 根据 LocalTime 采用默认 yyyy-MM-dd HH:mm:ss.SSS 格式 获取 String
     *
     * @param dateTime
     * @return {@link String}
     */
    public static String formatDateTimeMsSplit(LocalDateTime dateTime) {
        return dateTime.format(DATETIME_MS_FORMATTER_SPLIT);
    }

    /**
     * 返回当前的时间 yyyy年MM月dd日 HH时mm分ss秒
     *
     * @return {@link String}
     */
    public static String formatDateTimeSplitZh() {
        return formatDateTimeSplitZh(LocalDateTime.now());
    }

    /**
     * 根据 LocalDateTime 采用默认 yyyy年MM月dd日 HH时mm分ss秒 格式 获取 String
     *
     * @param datetime
     * @return {@link String}
     */
    public static String formatDateTimeSplitZh(LocalDateTime datetime) {
        return datetime.format(DATETIME_FORMATTER_SPLIT_ZH);
    }

    /**
     * 根据字符串 yyyy-MM-dd 获取最小的  yyyy-MM-dd HH:mm:ss 字符串
     *
     * @param date
     * @return {@link String}
     */
    public static String formatDateTimeMinOfDateSplit(String date) {
        return convertDateTimeMin(LocalDate.parse(date, DATE_FORMATTER_SPLIT)).format(DATETIME_MS_FORMATTER_SPLIT);
    }

    /**
     * 根据字符串 yyyy-MM-dd 获取最大的  yyyy-MM-dd HH:mm:ss 字符串
     *
     * @param date
     * @return {@link String}
     */
    public static String formatDateTimeMaxOfDateSplit(String date) {
        return convertDateTimeMax(LocalDate.parse(date, DATE_FORMATTER_SPLIT)).format(DATETIME_MS_FORMATTER_SPLIT);
    }

    /****************************************    【格式化】  月  **********************************************/

    /**
     * 返回当前的时间 yyMM
     *
     * @return {@link String}
     */
    public static String formatMonth() {
        return LocalDate.now().format(MONTH_FORMATTER);
    }

    /**
     * 根据 LocalDate 采用默认 yyyyMM 格式 获取 String
     *
     * @param date
     * @return {@link String}
     */
    public static String formatMonth(LocalDate date) {
        return date.format(MONTH_FORMATTER);
    }

    /**
     * 根据 LocalDate 采用默认 yyyy-MM 格式 获取 String
     *
     * @param date
     * @return {@link String}
     */
    public static String formatMonthSplit(LocalDate date) {
        return date.format(MONTH_FORMATTER_SPLIT);
    }

    /****************************************    【格式化】  年  **********************************************/

    /**
     * 根据 LocalDate 采用默认 yyyy 格式 获取 String
     *
     * @param date
     * @return {@link String}
     */
    public static String formatYear(LocalDate date) {
        return date.format(YEAR_FORMATTER);
    }

    /****************************************    【转换】 日期  **********************************************/

    /**
     * 根据 字符串 采用默认 yyyyMMdd 格式 获取 LocalDate
     *
     * @param date
     * @return {@link LocalDate}
     */
    public static LocalDate convertDate(String date) {
        return LocalDate.parse(date, DATE_FORMATTER);
    }

    /**
     * 根据 格式 返回指定日期字符串的 LocalDate
     *
     * @param date
     * @param pattern
     * @return {@link LocalDate}
     */
    public static LocalDate convertDate(String date, String pattern) {
        return LocalDate.parse(date, DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * Date 转换 LocalDate
     * atZone()方法返回在指定时区从此Instant生成的ZonedDateTime。
     *
     * @param date
     * @return {@link LocalDate}
     */
    public static LocalDate convertDate(Date date) {
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * 根据 字符串 采用默认 yyyy-MM-dd 格式 获取 LocalDate
     *
     * @param date
     * @return {@link LocalDate}
     */
    public static LocalDate convertDateSplit(String date) {
        return LocalDate.parse(date, DATE_FORMATTER_SPLIT);
    }

    /****************************************    【转换】 时间  **********************************************/

    /**
     * 根据 格式 返回指定时间字符串的 LocalTime
     *
     * @param time
     * @param pattern
     * @return {@link LocalTime}
     */
    public static LocalTime convertTime(String time, String pattern) {
        return LocalTime.parse(time, DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 根据 字符串 采用默认 HHmmss 格式 获取 LocalTime
     *
     * @param time
     * @return {@link LocalTime}
     */
    public static LocalTime convertTime(String time) {
        return LocalTime.parse(time, TIME_FORMATTER);
    }

    /****************************************    【转换】 日期时间  **********************************************/

    /**
     * 根据 字符串 采用默认 yyyyMMddHHmmss 格式 获取 LocalDateTime
     *
     * @param dateTime
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime convertDateTime(String dateTime) {
        return LocalDateTime.parse(dateTime, DATETIME_FORMATTER);
    }

    /**
     * Date 转换 LocalDateTime
     * atZone()方法返回在指定时区从此Instant生成的ZonedDateTime。
     *
     * @param date
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime convertDateTime(Date date) {
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    /**
     * 根据 格式 返回指定日期时间字符串的 LocalDateTime
     *
     * @param dateTime
     * @param pattern
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime convertDateTime(String dateTime, String pattern) {
        return LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * LocalDate + LocalTime 转换 LocalDateTime
     *
     * @param date
     * @param time
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime convertDateTime(LocalDate date, LocalTime time) {
        return date.atTime(time);
    }

    /**
     * long(时间戳/毫秒值)转化LocalDateTime
     *
     * @param timestamp
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime convertDateTimeOfTimestamp(long timestamp) {
        Instant instant = Instant.ofEpochMilli(timestamp);
        ZoneId zone = ZoneId.systemDefault();
        return LocalDateTime.ofInstant(instant, zone);
    }

    /**
     * long(时间戳/秒值)转化LocalDateTime
     *
     * @param second
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime convertDateTimeOfSecond(long second) {
        Instant instant = Instant.ofEpochSecond(second);
        ZoneId zone = ZoneId.systemDefault();
        return LocalDateTime.ofInstant(instant, zone);
    }

    /**
     * 根据 字符串 采用默认 yyyy-MM-dd HH:mm:ss 格式 获取 LocalDateTime
     *
     * @param dateTime
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime convertDateTimeSplit(String dateTime) {
        return LocalDateTime.parse(dateTime, DATETIME_FORMATTER_SPLIT);
    }

    /**
     * 根据 字符串 采用默认 yyyy-MM-dd HH:mm:ss.SSS 格式 获取 LocalDateTime
     *
     * @param dateTime
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime convertDateTimeMsSplit(String dateTime) {
        return LocalDateTime.parse(dateTime, DATETIME_MS_FORMATTER_SPLIT);
    }

    /**
     * 根据 字符串 采用默认 yyyy年MM月dd日 HH时mm分ss秒 格式 获取 LocalDateTime
     *
     * @param dateTime
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime convertDateTimeSplitZh(String dateTime) {
        return LocalDateTime.parse(dateTime, DATETIME_FORMATTER_SPLIT_ZH);
    }

    /**
     * 根据字符串 yyyy-MM-dd 获取最小的 LocalDateTime 时间
     *
     * @param date
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime convertDateTimeMinOfDateSplit(String date) {
        return convertDateTimeMin(LocalDate.parse(date, DATE_FORMATTER_SPLIT));
    }

    /**
     * 获取 LocalDate 获取最小的 LocalDateTime 时间
     *
     * @param date
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime convertDateTimeMin(LocalDate date) {
        return convertDateTime(date, LocalTime.MIN);
    }

    /**
     * 根据字符串  yyyy-MM-dd 获取最大的 LocalDateTime 时间
     *
     * @param date
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime convertDateTimeMaxOfDateSplit(String date) {
        return convertDateTimeMax(LocalDate.parse(date, DATE_FORMATTER_SPLIT));
    }

    /**
     * 根据 LocalDate 获取最大的 LocalDateTime 时间
     *
     * @param date
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime convertDateTimeMax(LocalDate date) {
        return convertDateTime(date, LocalTime.MAX);
    }


    /****************************************    【间隔】    **********************************************/

    /**
     * 日期相隔年份
     *
     * @param startInclusive
     * @param endExclusive
     * @return {@link long}
     */
    public static long gapYears(Temporal startInclusive, Temporal endExclusive) {
        return startInclusive.until(endExclusive, ChronoUnit.YEARS);
    }

    /**
     * 日期相隔月份
     *
     * @param startInclusive
     * @param endExclusive
     * @return {@link long}
     */
    public static long gapMonths(Temporal startInclusive, Temporal endExclusive) {
        return startInclusive.until(endExclusive, ChronoUnit.MONTHS);
    }

    /**
     * 日期相隔天数
     * .getDays()只是获得年月日中日的差值，还有.getYears()和.getMonths()来分别获取年份和月份的差值。
     * return Period.between(startDateInclusive, endDateExclusive).getDays();
     * 所以计算间隔天数不能使用这个工具方法
     *
     * @param startDateInclusive
     * @param endDateExclusive
     * @return {@link long}
     */
    public static long gapDays(LocalDate startDateInclusive, LocalDate endDateExclusive) {
        return endDateExclusive.toEpochDay() - startDateInclusive.toEpochDay();
    }

    /**
     * 日期相隔小时
     *
     * @param startInclusive
     * @param endExclusive
     * @return {@link long}
     */
    public static long gapHours(Temporal startInclusive, Temporal endExclusive) {
        return Duration.between(startInclusive, endExclusive).toHours();
    }

    /**
     * 日期相隔分钟
     *
     * @param startInclusive
     * @param endExclusive
     * @return {@link long}
     */
    public static long gapMinutes(Temporal startInclusive, Temporal endExclusive) {
        return Duration.between(startInclusive, endExclusive).toMinutes();
    }

    /**
     * 日期相隔秒数
     *
     * @param startInclusive
     * @param endExclusive
     * @return {@link long}
     */
    public static long gapSeconds(Temporal startInclusive, Temporal endExclusive) {
        return Duration.between(startInclusive, endExclusive).getSeconds();
    }

    /**
     * 日期相隔毫秒数
     *
     * @param startInclusive
     * @param endExclusive
     * @return {@link long}
     */
    public static long gapMillis(Temporal startInclusive, Temporal endExclusive) {
        return Duration.between(startInclusive, endExclusive).toMillis();
    }

    /****************************************    【累加】   **********************************************/

    /**
     * 时间累加天数
     * 通过默认格式 yyyy-MM-dd HH:mm:ss 的字符串 添加 days 天数 返回LocalDateTime
     *
     * @param dateTime "2019-01-16 14:30:00"
     * @param days     天数
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime plusDaysOfDateTimeSplit(String dateTime, long days) {
        return plusDays(LocalDateTime.parse(dateTime, DATETIME_FORMATTER_SPLIT), days);
    }

    /**
     * 时间累加天数
     * 通过 LocalDateTime 添加 days 的天数 返回 LocalDateTime
     *
     * @param dateTime
     * @param days
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime plusDays(LocalDateTime dateTime, long days) {
        return dateTime.plusDays(days);
    }

    /**
     * 时间累加天数
     * 通过默认格式 yyyy-MM-dd  的字符串 添加 days 天数 返回LocalDateTime
     *
     * @param date
     * @param days
     * @return {@link LocalDate}
     */
    public static LocalDate plusDaysOfDateSplit(String date, long days) {
        return plusDays(LocalDate.parse(date, DATE_FORMATTER_SPLIT), days);
    }

    /**
     * 时间累加天数
     * 通过 LocalDate 添加 days 的天数 返回 LocalDate
     *
     * @param date
     * @param days
     * @return {@link LocalDate}
     */
    public static LocalDate plusDays(LocalDate date, long days) {
        return date.plusDays(days);
    }

    /**
     * 时间累加秒
     * 通过 LocalDateTime 添加 seconds 秒值 返回 LocalDateTime
     *
     * @param dateTime
     * @param seconds
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime plusSeconds(LocalDateTime dateTime, long seconds) {
        return dateTime.plusSeconds(seconds);
    }

    /**
     * 时间累加分钟
     * 通过 LocalDateTime 添加 minutes 分钟值 返回 LocalDateTime
     *
     * @param dateTime
     * @param minutes
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime plusMinutes(LocalDateTime dateTime, long minutes) {
        return dateTime.plusMinutes(minutes);
    }

    /****************************************    【递减】   **********************************************/

    /**
     * 时间累减天数
     * 通过默认格式 yyyy-MM-dd HH:mm:ss 的字符串 递减 days 天数 返回LocalDateTime
     *
     * @param dateTime
     * @param days
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime minusDaysOfDateTimeSplit(String dateTime, long days) {
        return minusDays(LocalDateTime.parse(dateTime, DATETIME_FORMATTER_SPLIT), days);
    }

    /**
     * 时间累减天数
     * 通过 LocalDateTime 递减 days 天数  返回 LocalDateTime
     *
     * @param dateTime
     * @param days
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime minusDays(LocalDateTime dateTime, long days) {
        return dateTime.minusDays(days);
    }

    /**
     * 时间累减天数
     * 通过默认格式 yyyy-MM-dd 的字符串 递减 days 天数 返回LocalDateTime
     *
     * @param date "2019-01-16"
     * @param days 天数
     * @return {@link LocalDate}
     */
    public static LocalDate minusDaysOfDateSplit(String date, long days) {
        return minusDays(LocalDate.parse(date, DATE_FORMATTER_SPLIT), days);
    }

    /**
     * 时间累减天数
     * 通过 LocalDate 递减 days 的天数 返回 LocalDate
     *
     * @param date
     * @param days
     * @return {@link LocalDate}
     */
    public static LocalDate minusDays(LocalDate date, long days) {
        return date.minusDays(days);
    }

    /**
     * 时间累减秒值
     * 通过 LocalDateTime 递减 seconds 秒值  返回 LocalDateTime
     *
     * @param dateTime
     * @param seconds
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime minusSeconds(LocalDateTime dateTime, long seconds) {
        return dateTime.minusSeconds(seconds);
    }

    /**
     * 时间累减分钟
     * 通过 LocalDateTime 递减 minutes 分钟  返回 LocalDateTime
     *
     * @param dateTime
     * @param minutes
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime minusMinutes(LocalDateTime dateTime, long minutes) {
        return dateTime.minusMinutes(minutes);
    }

    /****************************************    【unit计算】   **********************************************/

    /**
     * 按照 unit 保留单位时间的起始值
     *
     * @param time
     * @param unit
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime floorUnit(LocalDateTime time, ChronoUnit unit) {

        return switch (unit) {
            case YEARS -> LocalDateTime.of(time.getYear(), 1, 1, 0, 0);
            case MONTHS -> LocalDateTime.of(time.getYear(), time.getMonthValue(), 1, 0, 0);
            case DAYS -> LocalDateTime.of(time.getYear(), time.getMonthValue(), time.getDayOfMonth(), 0, 0);
            case HOURS ->
                    LocalDateTime.of(time.getYear(), time.getMonthValue(), time.getDayOfMonth(), time.getHour(), 0);
            case MINUTES ->
                    LocalDateTime.of(time.getYear(), time.getMonthValue(), time.getDayOfMonth(), time.getHour(), time.getMinute());
            case SECONDS ->
                    LocalDateTime.of(time.getYear(), time.getMonthValue(), time.getDayOfMonth(), time.getHour(), time.getMinute(), time.getSecond());
            default -> throw new IllegalStateException("Unexpected value: " + unit);
        };
    }

    /**
     * 按照 unit 计算间隔值
     *
     * @param startInclusive
     * @param endExclusive
     * @param unit
     * @return {@link long}
     */
    public static long gapUnit(LocalDateTime startInclusive, LocalDateTime endExclusive, ChronoUnit unit) {

        return switch (unit) {
            case YEARS -> gapYears(startInclusive, endExclusive);
            case MONTHS -> gapMonths(startInclusive, endExclusive);
            case DAYS -> gapDays(startInclusive.toLocalDate(), endExclusive.toLocalDate());
            case HOURS -> gapHours(startInclusive, endExclusive);
            case MINUTES -> gapMinutes(startInclusive, endExclusive);
            case SECONDS -> gapSeconds(startInclusive, endExclusive);
            default -> throw new IllegalStateException("Unexpected value: " + unit);
        };
    }

}